#include "aop.h"
#include <iostream> 
#include <fstream> 


#define FILENAMESIZE 200

class   LOGFile

{
public:
	LOGFile(char * fn);
	~LOGFile() ;

	int Open() ;
	int Append(char * line);
	int Close();
	int Delete();

private:
	char file_name[FILENAMESIZE];
	ofstream file;
	bool file_is_open;

};


LOGFile::LOGFile(char * fn)
	{

       memset((void *) & file_name,0,FILENAMESIZE);
		strcpy(file_name,fn);
		file_is_open=false;
	
	}

LOGFile::~LOGFile() {};

int LOGFile::Open() 
	{ 
		file.open (file_name,std::ios_base::app);

		file_is_open=true;
		return 0;
	};


int LOGFile::Append(char * line)
	{

		this->Open();

		file << line <<endl;
		this->Close();

		return 0;

	};


int LOGFile::Close()

	{

		file.close();
		file_is_open=false;

		return 0;
	}


int LOGFile::Delete()

{


	DeleteFile(file_name);

	return 0;

}
class AspectA : public Aspect {
public :
	int aspectalocal;

	void advice() 
	
	{ 
	  aspectalocal=20;

	   cout << " aspect A advice with local value = "<< aspectalocal<< " \n";
	   
	   cout << " join point method name is "<< GetJPMethodName() <<endl;
	   cout << " join point class  name is "<< GetJPClassName() <<endl;
	   
	   
	};
 AspectA(){ id=0;} ;



} ;


class AspectB : public Aspect {
public :
	int aspectblocal;
	LOGFile * log_file;
	char buffer[500];


	void advice() 
	
	{ 
	
		//sprintf(buffer," %s :: %s",,GetJPMethodName() );

		strcpy(buffer,GetJPClassName().c_str());
		strcat(buffer,"::");
		strcat(buffer,GetJPMethodName().c_str());


		log_file->Append(buffer);
	
	};


	void InitLogFile( char * file_name)
	{

		log_file = new LOGFile(file_name);

	};


 AspectB(){ id=1;} ;



};

 struct AspectType { 
     int id; 
 union {AspectA * AspectAptr ;AspectB * AspectBptr ; 
 } aspect ; 
  } ; 

class Aspectnode 
{
public:
	Aspectnode () { };
	Aspectnode (  AspectType thedata, Aspectnode * thenext) {
		      AspectValue=thedata;
              next=thenext;
              }

	Aspectnode * getnext() { return next;}; 
 

	void   setAspectValue( AspectType  thedata)  {AspectValue=thedata;};
	AspectType    getAspectValue() { return AspectValue;};

  void   setnext( Aspectnode * pointer) { next=pointer;} ;
  public:
    AspectType AspectValue;
    Aspectnode * next;
};

typedef Aspectnode * Aspectnodeptr;

 void  addhead_aspecnode( Aspectnodeptr & head, Aspectnodeptr & tail,Aspectnodeptr data)

                { 
                  data->setnext(head);  
                  head=data;
                  if (tail==NULL) 
                        tail=head;  }
//*****************************************************************
//*****************************************************************

  void freelist_aspectnode ( Aspectnodeptr &head) 
       {
           Aspectnodeptr tmp;
          
           while (head!=NULL)
                { tmp=head->getnext();
                  delete head;
                  head= tmp;
                }    
          } // end of free list
//*****************************************************************
//*****************************************************************
  
  void  addtail_aspectnode( Aspectnodeptr & head, Aspectnodeptr & tail,Aspectnodeptr data )
                { 
                  data->setnext(NULL);
                    if (head ==NULL) 
                      head=tail=data;
                    else
                  {  
                    tail->setnext(data);
                    tail=data;
                  } 
           }

struct MethodInfo
{ string  name;
  string  man_name; // mangled name
  string  classname;
  string  return_type_text;
  int num_of_params;  
  namenodeptr  params_head,params_tail; // contains list of the aruguments types of the method if any 
  bool  before;
  Aspectnodeptr   beforeHead;
  Aspectnodeptr   beforeTail;
  bool  after;
  Aspectnodeptr   afterHead;
  Aspectnodeptr   afterTail;
  bool  around;
  Aspectnodeptr   aroundHead;
  Aspectnodeptr   aroundTail;
};
//*****************************************************************
//*****************************************************************
//****************************************
MethodInfo *  MethodMOP;

Aspectnodeptr  ActiveAspectsHead; 
Aspectnodeptr  ActiveAspectsTail; 
int num_of_methods;

void DAC_INIT()
 {
     ifstream in; int rc1;



in.open("C:\\MasterProject\\stage1\\stage1\\stage1\\MYOCC\\Debug\\MMD2.da");
	


      
        string str,nop_str,param_str; // the second one is to be used for number of paramerter str
	char str2[30], nop_str2[30];
	int loc,oldloc;

    
	 getline(in,str);  // Get the frist line from the file, if any.

	 for (int i=0; i< str.length(); i++)
		 str2[i]=str[i];

	 str2[str.length()]='\n';

         num_of_methods=atoi(str2);


	// cout << " num_of_methods is "<< num_of_methods<<"\n";

	  MethodMOP = new MethodInfo[num_of_methods];
              
               for ( int c=0; c<num_of_methods; c++)
{
                getline(in,str);
                
                loc=str.find(",",0);    
                
                MethodMOP[c].name=str.substr(0,loc);
                oldloc=loc+1;
                loc=str.find(",",oldloc);    
                MethodMOP[c].classname=str.substr(oldloc,loc-oldloc);
	            
	            oldloc=loc+1;
                loc=str.find(",",oldloc);    
                MethodMOP[c].return_type_text=str.substr(oldloc,loc-oldloc);
                
                oldloc=loc+1;
                loc=str.find(",",oldloc);    
                nop_str=str.substr(oldloc,loc-oldloc);
                               
                
                 MethodMOP[c].params_head=NULL;
                 MethodMOP[c].params_tail=NULL;
                
                 for (int i=0; i< nop_str.length(); i++)
                   nop_str2[i]=nop_str[i];

	             nop_str2[nop_str.length()]='\n';

            
                 MethodMOP[c].num_of_params=atoi(nop_str2);
                 
                 namenodeptr   param_ptr;
                 
                 for ( int param_count=1; param_count<= MethodMOP[c].num_of_params; param_count++)
                  {
                      oldloc=loc+1;
                      loc=str.find(",",oldloc);    
                      param_str=str.substr(oldloc,loc-oldloc);
                      param_ptr= new namenode (param_str,NULL);
                      addtail_name(MethodMOP[c].params_head,MethodMOP[c].params_tail,param_ptr);
                   }   
                                
				MethodMOP[c].before=false;
				MethodMOP[c].after=false;
				MethodMOP[c].around=false;
				MethodMOP[c].beforeHead=NULL;
				MethodMOP[c].beforeTail=NULL;
				MethodMOP[c].afterHead=NULL;
				MethodMOP[c].afterTail=NULL; 
				MethodMOP[c].aroundHead=NULL;
				MethodMOP[c].aroundTail=NULL; 		

                       // Try to get another line.
                }
    
    
    
    
// old line 129

	in.close();










}


bool methodmatch( PCD pc, int method_id)

{
      string t1,t2,t3;
	  t3="*";
	   t1=MethodMOP[method_id].name;
	t2=MethodMOP[method_id].classname;
		if (
			( (t1.compare(pc.getmethodPC().getvalue())==0)  || (t3.compare(pc.getmethodPC().getvalue())==0) )
			
			&& ( (t2.compare(pc.getclassPC().getvalue())==0) || (t3.compare(pc.getclassPC().getvalue())==0) )
			)

	        return true;
        else
            return false;       
} // end matchmethod




class _dac_returnvoidptrnode 
{
public:
  _dac_returnvoidptrnode () {};
 _dac_returnvoidptrnode ( void * thetext, _dac_returnvoidptrnode * thenext){
            
           
	           value=thetext;
              next=thenext;
              };
              
 _dac_returnvoidptrnode * getnext() const { return next;};
 
  void   settext( void *  thedata) 
     { 
	       
	             value=thedata;
      };
      
   
   void *   gettext()  {return value;}

  void   setnext( _dac_returnvoidptrnode * pointer) { next=pointer;}
  
private:
  void * value;
  _dac_returnvoidptrnode * next;
};

typedef _dac_returnvoidptrnode * _dac_returnvoidptrnodeptr;

   

void  removefromlist__dac_returnvoidptr( _dac_returnvoidptrnodeptr & head, _dac_returnvoidptrnodeptr & tail,_dac_returnvoidptrnodeptr data)
  
{
			_dac_returnvoidptrnodeptr p;

			p=head;

			if (head==NULL)  
				cout << " DAC++ error : dac_addayvopidptr is empty already" <<endl;

			else
			{
			if ((head==data) && (head==tail))    // means only one element in the list
			{ 
			   	
				delete head;   // list became empty
				head=tail=NULL;
			}

			else if (head==data) 
			{
				head=head->getnext();
				delete data;
			}

			else
					// means the value is in the middle or the last one  ( remove last one )

				{ 
					while (p->getnext()!=data)
						p=p->getnext();

					//p points at the one cell right before your database
                     
					p->setnext(data->getnext());
					if (data==tail) 
						  tail=p->getnext();
					delete data;

				}
		   

			}

}




//*****************************************************************
//*****************************************************************


	_dac_returnvoidptrnodeptr   addtolist__dac_returnvoidptr( _dac_returnvoidptrnodeptr & head, _dac_returnvoidptrnodeptr & tail,_dac_returnvoidptrnodeptr data)
 { 
                   _dac_returnvoidptrnodeptr temp;

	               data->setnext(NULL);
                    if (head ==NULL) 
					{ head=tail=data;
					}  
                    else
                  {  
                    tail->setnext(data);
                    tail=data;
					
                  } 

				  temp=tail;

				  return temp;
           }



// later define here a constant to use for the maximum size of void where the constant can be obtained duing stage1
// 

typedef void * _dac_voidptr;

typedef _dac_voidptr  _dac_arrayvoidptr[15];


class _dac_arrayvoidptrnode 
{
public:
  
  _dac_arrayvoidptrnode () {};
 _dac_arrayvoidptrnode ( _dac_arrayvoidptr thetext, _dac_arrayvoidptrnode * thenext){
            
           for (int i=0; i<15; i++) 
	           value[i]=thetext[i];
              next=thenext;
              };

   _dac_arrayvoidptrnode * getnext() const { return next;};

  void   settext( _dac_arrayvoidptr  thedata) 
     { 
	         for (int i=0; i<15; i++) 
	             value[i]=thedata[i];
      };
  
	 void *    gettext(int index)  {return value[index];};

  void   setnext( _dac_arrayvoidptrnode * pointer) { next=pointer;};


  _dac_arrayvoidptr value;
private:
  
  _dac_arrayvoidptrnode * next;
};

typedef _dac_arrayvoidptrnode * _dac_arrayvoidptrnodeptr;

void  removefromlist__dac_arrayvoidptr( _dac_arrayvoidptrnodeptr & head, _dac_arrayvoidptrnodeptr & tail,_dac_arrayvoidptrnodeptr data)
  
{
			_dac_arrayvoidptrnodeptr p;

			p=head;

			if (head==NULL)  
				cout << " DAC++ error : dac_addayvopidptr is empty already" <<endl;

			else
			{
			if ((head==data) && (head==tail))    // means only one element in the list
			{ 
			   	
				delete head;   // list became empty
				head=tail=NULL;
			}

			else if (head==data) 
			{
				head=head->getnext();
				delete data;
			}

			else
					// means the value is in the middle or the last one  ( remove last one )

				{ 
					while (p->getnext()!=data)
						p=p->getnext();

					//p points at the one cell right before your database
                     
					p->setnext(data->getnext());
					if (data==tail) 
						  tail=p->getnext();
					delete data;

				}
		   

			}

}




//*****************************************************************
//*****************************************************************


	_dac_arrayvoidptrnodeptr   addtolist__dac_arrayvoidptr( _dac_arrayvoidptrnodeptr & head, _dac_arrayvoidptrnodeptr & tail,_dac_arrayvoidptrnodeptr data)
 { 
                   _dac_arrayvoidptrnodeptr temp;

	               data->setnext(NULL);
                    if (head ==NULL) 
					{ head=tail=data;
					}  
                    else
                  {  
                    tail->setnext(data);
                    tail=data;
					
                  } 

				  temp=tail;

				  return temp;
           }



_dac_arrayvoidptrnodeptr _dac_act_rec_head=NULL;
_dac_arrayvoidptrnodeptr _dac_act_rec_tail=NULL;




   Aspectnodeptr  searchlist_aspecnode ( Aspectnodeptr  head,Aspect * key)
   { 
   Aspectnodeptr temp;
   
   temp=NULL;
   
      int i=0,loc=-1;
      int found=0;
      while ((head !=NULL) &&( !found))
		  if ( ( head->AspectValue.id) ==key->id )
           { found=1; loc =i; temp=head; }
         else          
           { i++; head=head->getnext(); }  
   
   return temp;
      
   } // end of searchlist function
   
   
   

	 
void  removelist_aspectnode( Aspectnodeptr & head, Aspectnodeptr& tail,Aspectnodeptr data)
  
{
			Aspectnodeptr p;

			p=head;

			if (head==NULL)  
				cout << " DAC++ error : dac_addayvopidptr is empty already" <<endl;

			else
			{
			if ((head==data) && (head==tail))    // means only one element in the list
			{ 
			   	
				//delete head;   // list became empty
				head=tail=NULL;
			}

			else if (head==data) 
			{
				head=head->getnext();
				//delete data;
			}

			else
					// means the value is in the middle or the last one  ( remove last one )

				{ 
					while (p->getnext()!=data)
						p=p->getnext();

					//p points at the one cell right before your database
                     
					p->setnext(data->getnext());
					if (data==tail) 
						  tail=p->getnext();
					//delete data;

				}
		   

			}

}




string Aspect::GetJPMethodName()
{
 return MethodMOP[method_id].name;
}

string Aspect::GetJPClassName()
{
return MethodMOP[method_id].classname;
}
 void weave ( AspectA * asp) 
 { AspectType temp; 
 Aspectnode * aptr; 
 Message m; 
 string sen_msg;
 //cout << "  "<<endl;
temp.id=0; 
temp.aspect.AspectAptr=asp;
aptr = new Aspectnode(temp,NULL);
addhead_aspecnode(ActiveAspectsHead,ActiveAspectsTail,aptr);

 for (int k=0; k< num_of_methods; k++) { 
 if (methodmatch(asp->getpcd(), k)) 
 { if (asp->getweavespecs().getweavetype()==Before_T)  
  { MethodMOP[k].before=true;
    addhead_aspecnode(MethodMOP[k].beforeHead,MethodMOP[k].beforeTail,aptr); } 
 	  else if (asp->getweavespecs().getweavetype()==After_T)
    {   	MethodMOP[k].after=true;
 	addhead_aspecnode(MethodMOP[k].afterHead,MethodMOP[k].afterTail,aptr); 
	  } 
 } 
 }   
   } // end weave method 

 void weave ( AspectB * asp) 
 { AspectType temp; 
 Aspectnode * aptr; 
 Message m; 
 string sen_msg;
 //cout << "  "<<endl;
temp.id=1; 
temp.aspect.AspectBptr=asp;
aptr = new Aspectnode(temp,NULL);
addhead_aspecnode(ActiveAspectsHead,ActiveAspectsTail,aptr);

 for (int k=0; k< num_of_methods; k++) { 
 if (methodmatch(asp->getpcd(), k)) 
 { if (asp->getweavespecs().getweavetype()==Before_T)  
  { MethodMOP[k].before=true;
    addhead_aspecnode(MethodMOP[k].beforeHead,MethodMOP[k].beforeTail,aptr); } 
 	  else if (asp->getweavespecs().getweavetype()==After_T)
    {   	MethodMOP[k].after=true;
 	addhead_aspecnode(MethodMOP[k].afterHead,MethodMOP[k].afterTail,aptr); 
	  } 
 } 
 }   
   } // end weave method 

 void unweave ( AspectA * asp) 
 { Aspectnode * aptr; 
aptr = searchlist_aspecnode(ActiveAspectsHead,(Aspect *) asp);

 for (int k=0; k< num_of_methods; k++) { 
 if (methodmatch(asp->getpcd(), k)) 
 { if (asp->getweavespecs().getweavetype()==Before_T)  
  {
    removelist_aspectnode(MethodMOP[k].beforeHead,MethodMOP[k].beforeTail,aptr); } 
 	  else if (asp->getweavespecs().getweavetype()==After_T)
    {   	removelist_aspectnode(MethodMOP[k].afterHead,MethodMOP[k].afterTail,aptr); 
	  } 
 } 
 }   
   } // end unweave method 

 void unweave ( AspectB * asp) 
 { Aspectnode * aptr; 
aptr = searchlist_aspecnode(ActiveAspectsHead,(Aspect *) asp);

 for (int k=0; k< num_of_methods; k++) { 
 if (methodmatch(asp->getpcd(), k)) 
 { if (asp->getweavespecs().getweavetype()==Before_T)  
  {
    removelist_aspectnode(MethodMOP[k].beforeHead,MethodMOP[k].beforeTail,aptr); } 
 	  else if (asp->getweavespecs().getweavetype()==After_T)
    {   	removelist_aspectnode(MethodMOP[k].afterHead,MethodMOP[k].afterTail,aptr); 
	  } 
 } 
 }   
   } // end unweave method 

 void _dac_execute_after (int m_id, Aspectnodeptr _dac_ptr1, _dac_arrayvoidptrnodeptr _dac_ptr2) {
 
switch ( _dac_ptr1->AspectValue.id) 	{
 case 0:  _dac_ptr1->AspectValue.aspect.AspectAptr->method_id=m_id;
    _dac_ptr1->AspectValue.aspect.AspectAptr->advice();
   break;
 case 1:  _dac_ptr1->AspectValue.aspect.AspectBptr->method_id=m_id;
    _dac_ptr1->AspectValue.aspect.AspectBptr->advice();
   break;
 } ; 
 }; 
 void _dac_execute_before (int m_id,Aspectnodeptr _dac_ptr1, _dac_arrayvoidptrnodeptr _dac_ptr2) {
 
switch ( _dac_ptr1->AspectValue.id) 	{
 case 0:  _dac_ptr1->AspectValue.aspect.AspectAptr->method_id=m_id;
    _dac_ptr1->AspectValue.aspect.AspectAptr->advice();
   break;
 case 1:  _dac_ptr1->AspectValue.aspect.AspectBptr->method_id=m_id;
    _dac_ptr1->AspectValue.aspect.AspectBptr->advice();
   break;
 } ; 
 }; 
 void _dac_execute_around (int m_id,Aspectnodeptr _dac_ptr1, _dac_arrayvoidptrnodeptr _dac_ptr2, bool * _dac_proceed) {
 
switch ( _dac_ptr1->AspectValue.id) 	{
 case 0:  _dac_ptr1->AspectValue.aspect.AspectAptr->method_id=m_id;
    _dac_ptr1->AspectValue.aspect.AspectAptr->advice();
   break;
 case 1:  _dac_ptr1->AspectValue.aspect.AspectBptr->method_id=m_id;
    _dac_ptr1->AspectValue.aspect.AspectBptr->advice();
   break;
 } ; 
 }; 
